using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class AlienMating {
	
	public const int MaxPower=12;
	public const int MinPower=0;

	public static GameObject duplicateAlien(AlienGenome source) {
		GameObject clone= (GameObject)GameObject.Instantiate(source.gameObject);
		
		AlienGenome cloneGenome= clone.GetComponent<AlienGenome>();
		cloneGenome.duplicate(source);
		
		return clone;
	}
	
	public static GameObject spawnAlien(int difficulty) {
		switch( difficulty ) {
			case 0:
				return randomAlien(3, 5, 0, 1);
			break;
			case 1:
				return randomAlien(3, 6, 0, 2);
			break;
			case 2:
				return randomAlien(2, 8, 1, 2);
			break;
			case 3:
				return randomAlien(2, 10, 1, 2);
			break;
			case 4:
				return randomAlien(4, 12, 1, 3);
			break;
			case 5:
				return randomAlien(4, 12, 1, 3);
			break;
			default:
				return randomAlien(1, MaxPower, 0, 3);
			break;			
		}
		
	}
	
	public static GameObject randomAlien(int lowestHigh=1, int highestHigh=MaxPower/2, int lowestLow=0, int highestLow=0) {
		GameObject child= (GameObject)GameObject.Instantiate(AlienResource.Resource.AlienPrefab);
		
		AlienGenome childGenome= child.GetComponent<AlienGenome>();
		childGenome.AlienName= AlienNames.getRandomName();
		
		Chromosome a= new Chromosome();
			a.Max= highestHigh;
			a.Min= highestLow;
		Chromosome b= new Chromosome();
			b.Max= lowestHigh;
			b.Min= lowestLow;
		
		
		recombineChromosome(a, b, childGenome.Defense);
		recombineChromosome(a, b, childGenome.Attack);
		recombineChromosome(a, b, childGenome.Speed);
		recombineChromosome(a, b, childGenome.Smarts);
		recombineChromosome(a, b, childGenome.Strength);
		
		childGenome.generatePhenotype();
		//Make a big list of phenym
		foreach(Chromosome.ChromosomeType type in Enum.GetValues(typeof(Chromosome.ChromosomeType))){
			foreach(GameObject phenym in childGenome.getChromosome(type).Phenotype)
				childGenome.Phenotype.Add(phenym);
		}
		List<GameObject> leftOver= applyPhenotype(childGenome, applyPhenotype(childGenome, childGenome.Phenotype, false), true);
		foreach(GameObject left in leftOver) {
			left.SetActiveRecursively(false);	
		}

		return child;
	}
	
	public static GameObject generateChild(AlienGenome pA, AlienGenome pB) {
		GameObject child= (GameObject)GameObject.Instantiate(AlienResource.Resource.AlienPrefab);
		AlienGenome childGenome= child.GetComponent<AlienGenome>();
		childGenome.AlienName= AlienNames.getRandomName();
		childGenome.Generation= pA.Generation + 1;
		
		recombineChromosome(pA.Defense, pB.Defense, childGenome.Defense);
		recombineChromosome(pA.Attack, pB.Attack, childGenome.Attack);
		recombineChromosome(pA.Speed, pB.Speed, childGenome.Speed);
		recombineChromosome(pA.Smarts, pB.Smarts, childGenome.Smarts);
		recombineChromosome(pA.Strength, pB.Strength, childGenome.Strength);
//		childGenome.Defense.Phenotype= GenePool.CombinePhenotypes(pA.Defense, pB.Defense);
//		childGenome.Attack.Phenotype= GenePool.CombinePhenotypes(pA.Attack, pB.Attack);
//		childGenome.Speed.Phenotype= GenePool.CombinePhenotypes(pA.Speed, pB.Speed);
//		childGenome.Smarts.Phenotype= GenePool.CombinePhenotypes(pA.Smarts, pB.Smarts);
//		childGenome.Strength.Phenotype= GenePool.CombinePhenotypes(pA.Strength, pB.Strength);
		//childGenome.generatePhenotype();
		//Make a big list of phenym
		foreach(Chromosome.ChromosomeType type in Enum.GetValues(typeof(Chromosome.ChromosomeType))){
			foreach(GameObject phenym in childGenome.getChromosome(type).Phenotype)
				childGenome.Phenotype.Add(phenym);
		}
		List<GameObject> leftOver= applyPhenotype(childGenome, applyPhenotype(childGenome, childGenome.Phenotype, false), true);
		foreach(GameObject left in leftOver) {
			left.SetActiveRecursively(false);	
		}
		
		
		return child;
	}
	
	public static Chromosome recombineChromosome ( Chromosome pA, Chromosome pB, Chromosome child ) {
			
		int highestHigh, lowestHigh;
		int highestLow, lowestLow;

		
		if(pA.Min > pB.Min) {
			highestLow= pA.Min;
			lowestLow= pB.Min;
		}
		else{
			highestLow= pB.Min;
			lowestLow= pA.Min;
		}
		
		if(pA.Max > pB.Max) {
			highestHigh= pA.Max;
			lowestHigh= pB.Max;
		}
		else{
			highestHigh= pB.Max;
			lowestHigh= pA.Max;
		}
		
		//swap if there is an overlap
		if(lowestHigh < highestLow) {
			int temp= highestLow;
			highestLow= lowestHigh;
			lowestLow= temp;
		}
		
		child.Min = UnityEngine.Random.Range(lowestLow, highestLow+1);
		child.Max = UnityEngine.Random.Range(lowestHigh, highestHigh+1);
		child.Phenotype= GenePool.CombinePhenotypes(pA, pB);
		
		return child;	
	}
	
	private static List<GameObject> applyPhenotype(AlienGenome genome, List<GameObject> phenotype, bool secondCase) {
		Transform skel= genome.gameObject.transform.FindChild("FlyingSkeleton");
		
		Transform _base= skel.FindChild("Flying_Base");
		Transform eyeL= skel.FindChild("Eye_L");
		Transform eyeR= skel.FindChild("Eye_R");
		Transform limbL= skel.FindChild("Limb_L");
		Transform limbM= skel.FindChild("Limb_M");
		Transform limbR= skel.FindChild("Limb_R");		
		Transform handR= skel.FindChild("Limb_R/Hand");
		Transform handL= skel.FindChild("Limb_L/Hand");
		Transform handM= skel.FindChild("Limb_M/Hand");		
		Transform earR= skel.FindChild("Ear_R");		
		Transform earL= skel.FindChild("Ear_L");		
		Transform mouth= skel.FindChild("Mouth");
		Transform wingL= skel.FindChild("Wing_L");
		Transform wingR= skel.FindChild("Wing_R");
		Transform decoration= skel.FindChild("Decoration_1");
		Transform decoration2= skel.FindChild("Decoration_2");
		Transform decoration3= skel.FindChild("Decoration_3");
		Transform decoration4= skel.FindChild("Decoration_4");
			
		List<GameObject> secondPass= new List<GameObject>();
		
		foreach(GameObject phenym in phenotype) {
			string name= phenym.name.Replace("(Clone)", "");
		//	Debug.Log("Place: [" + name + "] onto: " + genome.gameObject.name);
			switch (name) {
				case "EyeOval":
				case "EyeRound":
				//case "EyeStalk":
					if(eyeL != null && eyeR != null) {
						if(UnityEngine.Random.Range(0,2) == 0 )
							append(ref eyeL, phenym.transform, null);
						else 
							append(ref eyeR, phenym.transform, null);
					}
					else if (eyeR != null)
						append(ref eyeR, phenym.transform, null);
					else if (eyeL != null)
						append(ref eyeL, phenym.transform, null);
					else
						secondPass.Add(phenym);
				break;
				case "coveredEar":
				case "earStalk":
					if (earL != null)
						append(ref earL, phenym.transform, genome);
					else if (earR != null)
						append(ref earR, phenym.transform, genome);
					else
						secondPass.Add(phenym);				
				break;
				case "Snout":
				case "Trunk": 
					if (mouth != null)
						append(ref mouth, phenym.transform, genome);
					else
						secondPass.Add(phenym);
				break;	
				case "LongHorn":
				case "smallHorn":
				case "curvedHorn":
				case "stud":
					if(earR != null) {
						append(ref earR, phenym.transform, null);
					}
					else if(earL != null)
						append(ref earL, phenym.transform, null);
					else if(decoration != null) {
						append(ref decoration, phenym.transform, null);
					}
					else if(decoration2 != null)
						append(ref decoration2, phenym.transform, null);
					else if(decoration3 != null)
						append(ref decoration3, phenym.transform, null);
					else if(decoration4 != null)
						append(ref decoration4, phenym.transform, null);
					else
						secondPass.Add(phenym);
				break;
				case "hand":
				case "hoof":
				case "claws":
				case "Blade":
					if (handR != null)
						append(ref handR, phenym.transform, null);
					else if (handL != null)
						append(ref handL, phenym.transform, null);
					else if (handM != null)
						append(ref handM, phenym.transform, null);
					else if (secondCase) {
						if (limbL!= null) append(ref limbL, phenym.transform, null);
						else if (limbM!= null) append(ref limbM, phenym.transform, null);
						else if (limbR!= null) append(ref limbR, phenym.transform, null);
						else
							secondPass.Add(phenym);
					}
					else
						secondPass.Add(phenym);
				break;
				case "HeadFlat":
				case "HeadRound":
					if (_base != null)
						append(ref _base, phenym.transform, genome);
					else
						secondPass.Add(phenym);
				break;			
				case "LegNormal":
				case "Tentacle":
					if (limbR != null)
						append(ref limbR, phenym.transform, genome);
					else if (limbL != null)
						append(ref limbL, phenym.transform, genome);
					else if (limbM != null)
						append(ref limbM, phenym.transform, genome);
					else
						secondPass.Add(phenym);
				break;
				case "WingBat_Base":
					if(wingL != null && wingR != null) {
						append(ref wingL, phenym.transform.FindChild("wingBat_L"), genome);
						append(ref wingR, phenym.transform.FindChild("wingBat_R"), genome);
					}
					else
						secondPass.Add(phenym);
				break;
				case "wingBug_Base":
					if(wingL != null && wingR != null) {
						append(ref wingL, phenym.transform.FindChild("WingBug_L"), genome);
						append(ref wingR, phenym.transform.FindChild("WingBug_R"), genome);
					}
					else
						secondPass.Add(phenym);
				break;	
				case "Arm_Base":
					if(limbL != null && limbR != null) {
						append(ref limbL, phenym.transform.FindChild("Arm_L"), genome);
						append(ref limbR, phenym.transform.FindChild("Arm_R"), genome);
					}
					else secondPass.Add(phenym);
				break;	
				case "ArmStub_base":
					if(limbL != null && limbR != null) {
						append(ref limbL, phenym.transform.FindChild("armStub_L"), genome);
						append(ref limbR, phenym.transform.FindChild("armStub_R"), genome);
					}
					else secondPass.Add(phenym);
				break;
				default:
					secondPass.Add(phenym);
				break;
			}
		}
		return secondPass;
	}
					
	static private void append(ref Transform parent, Transform child, AlienGenome genome) {
		if (child!=null) {
			child.parent= parent;
			child.transform.localPosition= Vector3.zero;
			child.transform.localEulerAngles= Vector3.zero;
			if (child.name.Contains("Head")) child.transform.localScale= Vector3.one;
			if (genome!=null) child.renderer.material= genome.GetCoat();
		}
		else {
			Debug.LogError("Can't append a null child.");
		}
		parent= null;
	}
}


public class AlienNames {
	
	static string[] names= new string[]{
		"Jimbo",
		"Frank",
		"GorGax",
		"Flactulance",
		"Smargon",
		"Windosor",
		"Quatlukes",
		"Glazmer",
		"Ratch-it",
		"Winnifer",
		"Torbin",
		"Orblatz",
		"Unblent",
		"Norbit",
		"Yurt",
		"Mortifier",
		"Qzasdrd",
		"Zumbast",
		"Hortz",
		"Driph",
		"Rilph", "Vur", "Zim", "Creig", "Smast", "Korgon","Yevv", "Ignot", "Plak", "Rast", "Winst", "Bromidaion", "Belgium", "Flez", "Xat", "Nekriod", "Prims",
		"Hue","Smats", "Drafty", "Dysly", "Udrit", "Nummera", "Ysit", "Ydance", "Yromance" 
		
	};
	
	public static string getRandomName() {			
		return names[ UnityEngine.Random.Range(0, names.Length)];
	}	
}
